;*
;* misc.nas
;* Miscellaneous assembly functions
;*
;*---------------------------------------------------------------------------
;* Copyright 1998-2006 Randy Heit
;* All rights reserved.
;*
;* Redistribution and use in source and binary forms, with or without
;* modification, are permitted provided that the following conditions
;* are met:
;*
;* 1. Redistributions of source code must retain the above copyright
;*    notice, this list of conditions and the following disclaimer.
;* 2. Redistributions in binary form must reproduce the above copyright
;*    notice, this list of conditions and the following disclaimer in the
;*    documentation and/or other materials provided with the distribution.
;* 3. The name of the author may not be used to endorse or promote products
;*    derived from this software without specific prior written permission.
;*
;* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
;* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
;* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
;* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
;* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
;* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
;* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
;* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
;* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;*---------------------------------------------------------------------------
;*

BITS 32

%ifndef M_TARGET_LINUX

%define DoBlending_MMX	_DoBlending_MMX
%define BestColor_MMX	_BestColor_MMX

%endif

%ifdef M_TARGET_WATCOM
  SEGMENT DATA PUBLIC ALIGN=16 CLASS=DATA USE32
  SEGMENT DATA
%else
  SECTION .data
%endif

Blending256:
	dd	0x01000100,0x00000100

%ifdef M_TARGET_WATCOM
  SEGMENT CODE PUBLIC ALIGN=16 CLASS=CODE USE32
  SEGMENT CODE
%else
  SECTION .text
%endif

;-----------------------------------------------------------
;
; DoBlending_MMX
;
; MMX version of DoBlending
;
; (DWORD *from, DWORD *to, count, tor, tog, tob, toa)
;-----------------------------------------------------------

GLOBAL	DoBlending_MMX

DoBlending_MMX:
		pxor		mm0,mm0			; mm0 = 0
		mov			eax,[esp+4*4]
		shl			eax,16
		mov			edx,[esp+4*5]
		shl			edx,8
		or			eax,[esp+4*6]
		or			eax,edx
		mov			ecx,[esp+4*3]	; ecx = count
		movd		mm1,eax			; mm1 = 00000000 00RRGGBB
		mov			eax,[esp+4*7]
		shl			eax,16
		mov			edx,[esp+4*7]
		shl			edx,8
		or			eax,[esp+4*7]
		or			eax,edx
		mov			edx,[esp+4*2]	; edx = dest
		movd		mm6,eax			; mm6 = 00000000 00AAAAAA
		punpcklbw	mm1,mm0			; mm1 = 000000RR 00GG00BB
		movq		mm7,[Blending256]
		punpcklbw	mm6,mm0			; mm6 = 000000AA 00AA00AA
		mov			eax,[esp+4*1]	; eax = source
		pmullw		mm1,mm6			; mm1 = 000000RR 00GG00BB (multiplied by alpha)
		psubusw		mm7,mm6			; mm7 = 000000aa 00aa00aa (one minus alpha)
		nop							; Does this actually pair on a Pentium?

; Do four colors per iteration: Count must be a multiple of four.

.loop	movq		mm2,[eax]	; mm2 = 00r2g2b2 00r1g1b1
		add			eax,8
		movq		mm3,mm2		; mm3 = 00r2g2b2 00r1g1b1
		punpcklbw	mm2,mm0		; mm2 = 000000r1 00g100b1
		punpckhbw	mm3,mm0		; mm3 = 000000r2 00g200b2
		pmullw		mm2,mm7		; mm2 = 0000r1rr g1ggb1bb
		add			edx,8
		pmullw		mm3,mm7		; mm3 = 0000r2rr g2ggb2bb
		sub			ecx,2
		paddusw		mm2,mm1
		psrlw		mm2,8
		paddusw		mm3,mm1
		psrlw		mm3,8
		packuswb	mm2,mm3		; mm2 = 00r2g2b2 00r1g1b1
		movq		[edx-8],mm2

		movq		mm2,[eax]	; mm2 = 00r2g2b2 00r1g1b1
		add			eax,8
		movq		mm3,mm2		; mm3 = 00r2g2b2 00r1g1b1
		punpcklbw	mm2,mm0		; mm2 = 000000r1 00g100b1
		punpckhbw	mm3,mm0		; mm3 = 000000r2 00g200b2
		pmullw		mm2,mm7		; mm2 = 0000r1rr g1ggb1bb
		add			edx,8
		pmullw		mm3,mm7		; mm3 = 0000r2rr g2ggb2bb
		sub			ecx,2
		paddusw		mm2,mm1
		psrlw		mm2,8
		paddusw		mm3,mm1
		psrlw		mm3,8
		packuswb	mm2,mm3		; mm2 = 00r2g2b2 00r1g1b1
		movq		[edx-8],mm2
		
		jnz			.loop

		emms
		ret

;-----------------------------------------------------------
;
; BestColor_MMX
;
; Picks the closest matching color from a palette
;
; Passed FFRRGGBB and palette array in same format
; FF is the index of the first palette entry to consider
;
;-----------------------------------------------------------

GLOBAL	BestColor_MMX
GLOBAL	@BestColor_MMX@8

BestColor_MMX:
		mov			ecx,[esp+4]
		mov			edx,[esp+8]
@BestColor_MMX@8:
		pxor		mm0,mm0
		movd		mm1,ecx			; mm1 = color searching for
		mov			eax,257*257+257*257+257*257	;eax = bestdist
		push		ebx
		punpcklbw	mm1,mm0
		mov			ebx,ecx			; ebx = best color
		shr			ecx,24			; ecx = count
		and			ebx,0xffffff
		push		esi
		push		ebp

.loop	movd		mm2,[edx+ecx*4]	; mm2 = color considering now
		inc			ecx
		punpcklbw	mm2,mm0
		movq		mm3,mm1
		psubsw		mm3,mm2
		pmullw		mm3,mm3			; mm3 = color distance squared

		movd		ebp,mm3			; add the three components
		psrlq		mm3,32			; into ebp to get the real
		mov			esi,ebp			; (squared) distance
		shr			esi,16
		and			ebp,0xffff
		add			ebp,esi
		movd		esi,mm3
		add			ebp,esi

		jz			.perf			; found a perfect match
		cmp			eax,ebp
		jb			.skip
		mov			eax,ebp
		lea			ebx,[ecx-1]
.skip	cmp			ecx,256
		jne			.loop
		mov			eax,ebx
		pop			ebp
		pop			esi
		pop			ebx
		emms
		ret

.perf	lea		eax,[ecx-1]
		pop		ebp
		pop		esi
		pop		ebx
		emms
		ret
